﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Linq;
using ClickLand.CorporacionPlaza.Presentacion.Contratos.AdministracionContrato;
using ClickLand.CorporacionPlaza.Presentacion.Controladores;
using ClickLand.CorporacionPlaza.Presentacion.CorporacionPlazaWS;
using ClickLand.Web.UI.WebControls;

namespace ClickLand.CorporacionPlaza.Presentacion.Presentadores.AdministracionContrato
{
    /// <summary> Clase que hace de presentador para la vista del cuadro de proyecciones </summary>
    public class PresentadorProyeccionContrato:PresentadorBase
    {
        #region Atributos

        private readonly IProyeccionContrato _vista;
        private readonly ControladorAdministracionContrato _controlador;

        #endregion

        #region Constructor

        /// <summary> Contructor de la clase </summary>
        /// <param name="vista">Propiedades de la vista</param>
        public PresentadorProyeccionContrato(IProyeccionContrato vista)
        {
            _vista = vista;
            _controlador = new ControladorAdministracionContrato();
        }

        #endregion
        
        #region Metodos

        /// <summary> Metodo que realiza las operaciones para realizar la carga de la pagina </summary>
        public void CargarPagina()
        {

            CargarListaConValor(_vista.TipoEstablecimientoBusqueda, "tipoEstablecimiento", true);
            //  CargarClientes();
        }


        /// <summary> Metodo que realiza la busqueda de contratos </summary>
        public void BuscarContrato()
        {
            ContratoDto contrato = new ContratoDto();
            EstablecimientoDto establecimiento = new EstablecimientoDto();
            if (Convert.ToInt32(_vista.TipoEstablecimientoBusqueda.SelectedValue) != -1)
            {
                establecimiento.Tipo = new TipoEstablecimientoDto { Id = Convert.ToInt64(_vista.TipoEstablecimientoBusqueda.SelectedValue) };
                if (_vista.EstablecimientoBusqueda.Id != -1)
                    establecimiento.Id = _vista.EstablecimientoBusqueda.Id;
            }
            contrato.NombreComercial = _vista.NombreComercialBusqueda;
            if (!string.IsNullOrEmpty(_vista.NombreClienteBusqueda))
            {
                contrato.Cliente = new ClienteDto();
                contrato.Cliente.Nombre = _vista.NombreClienteBusqueda;
            }

            contrato.Estado = 1;
            _vista.ListaContratos = _controlador.BuscarContrato(contrato);

        }

        #endregion

        /// <summary>
        /// Metodo que realiza las operaciones para mostrar el cuadro de proyecciones
        /// </summary>
        /// <param name="id"></param>
        public void MostrarCuadroProyecciones(int id)
        {
            _vista.Contrato = _vista.ListaContratos[id];
            _vista.ListaProyeccion = ArmarProyeccion();
        }


        /// <summary> Metodo que arma el dataset para el cuadro de proyecciones </summary>
        /// <returns></returns>
        public DataSet ArmarProyeccion()
        {
            DataTable tabla = new DataTable();
            tabla.Columns.Add("Id");
            tabla.Columns.Add("NumeroLocal");
            tabla.Columns.Add("IdContrato");
            for (int i = 0; i < 12; i++)
            {
                tabla.Columns.Add("Mes" + i);
                tabla.Columns.Add("Monto" + i);
                tabla.Columns.Add("Porcentaje" + i);
                tabla.Columns.Add("Seleccionar" + i);
                tabla.Columns.Add("Pintar" + i);
                tabla.Columns.Add("Color" + i);
            }
            DataRow row;
            int fila = 0;
            var listaCanons = new List<ContratoPensionDto>();
            var listaInicio= new List<ContratoPensionDto>();
            var listaProyeccion = new List<ProyeccionDto>();
            foreach (var contrato in _vista.ListaContratos)
            {
                DateTime fecha = new DateTime(DateTime.Now.AddYears(-1).Year, 1, 1);
                listaCanons.AddRange(_controlador.ConsultarCanon(contrato, fecha));
                listaInicio.AddRange(_controlador.ConsultarCanon(contrato, contrato.FechaInicio.GetValueOrDefault()));
                listaProyeccion.AddRange(_controlador.ConsultarProyeccion(contrato));

            }

            for (int i = 0; i < 5; i++)
            {
                DateTime fecha = new DateTime(DateTime.Now.AddYears(i - 1).Year, 1, 1);

                foreach (var contrato in _vista.ListaContratos)
                {
                    row = tabla.NewRow();
                    row["IdContrato"] = contrato.Id;
                    float monto = 0;
                    for (int j = 0; j < 12; j++)
                    {
                        if((j == 0) && ( fila >= _vista.ListaContratos.Count))
                            monto = float.Parse( tabla.Rows[fila - _vista.ListaContratos.Count]["Monto11"].ToString());
                        else if (j > 0 )
                            monto = float.Parse(row["Monto" + (j-1)].ToString());
                        var fechaMes = new DateTime(fecha.Year, j + 1, 1);
                        DateTime fechaProyeccion = new DateTime(fechaMes.Year, fechaMes.Month, contrato.FechaInicio.GetValueOrDefault().Day);
                        float montoMes;
                        float porcentaje;
                        if(fechaMes <= contrato.FechaFin)
                        {

                            montoMes = ObtenerMontoContrato(listaCanons, fechaMes,contrato);
                            porcentaje = ObtenerPorcentajeContrato(listaCanons, fechaMes, contrato);
                        }
                        else
                        {
                            var proyeccion = ObtenerMontoProyeccion(listaProyeccion,contrato,fechaProyeccion);
                            montoMes = (float) (proyeccion != null
                                                    ? proyeccion.Monto
                                                    : (ObtenerMontoContrato(listaInicio, contrato.FechaFin, contrato) * 1.40));
                            porcentaje = (proyeccion != null)
                                                    ? proyeccion.Porcentaje
                                                    : 40;
                        }
                        row["Seleccionar" + j] = contrato.FechaFin < fechaMes;
                        row["Pintar" + j] = (!(monto > 0) && fechaMes < contrato.FechaInicio) || (montoMes > monto || montoMes < monto); 
                        if ((!(monto > 0) && fechaMes < contrato.FechaInicio))
                            row["Color" + j] = Color.Red.ToString();
                        else if (montoMes > monto || montoMes < monto)
                            row["Color" + j] = Color.Blue.ToString();
                        else
                            row["Color" + j] = Color.White.ToString();
                        monto = montoMes;
                        row["NumeroLocal"] = contrato.Establecimiento.Numero + " " + contrato.NombreComercial;
                        row["Mes" + j] = fechaProyeccion.ToString("dd-MM-yyyy");
                        row["Monto" + j] = monto.ToString("N");
                        row["Porcentaje" + j] = porcentaje.ToString("N");

                    }
                    fila++;
                    tabla.Rows.Add(row);
                }
            }

            DataSet dataSet = new DataSet();
            dataSet.Tables.Add(tabla);

            


            return dataSet;

        }


        /// <summary> Metodo que obtiene el monto de la proyeccion segun la fecha </summary>
        /// <param name="contrato"> </param>
        /// <param name="fecha"></param>
        /// <returns></returns>
        public ProyeccionDto ObtenerMontoProyeccion(List<ProyeccionDto> lista ,ContratoDto contrato, DateTime fecha)
        {
            ProyeccionDto retorno = null;
            if (lista.Count > 0)
            {
                var valor = lista.Where(
                    dto => (dto.Contrato.Id == contrato.Id && (dto.FechaInicio < fecha) && (dto.FechaFin > fecha)) || (dto.FechaInicio == fecha));
                if (valor.Any())
                    retorno = valor.FirstOrDefault();
                else
                {
                    foreach (var dto in lista.Where(dto => dto.Contrato.Id == contrato.Id))
                        if (dto.FechaFin == fecha)
                            retorno = dto;
                        else if (dto.FechaInicio == fecha)
                            retorno = dto;
                }
            }
            return retorno;
        }


        /// <summary> Metodo que almacena la informacion de la proyeccion </summary>
        public void Guardar()
        {
            List<ProyeccionDto> lista = new List<ProyeccionDto>();
            for (int i = 0; i < _vista.ListaProyeccion.Tables[0].Rows.Count; i++)
            {
                
                var fila = _vista.ListaProyeccion.Tables[0].Rows[i];
                var contrato = _vista.ListaContratos[i%_vista.ListaContratos.Count];
                for (int j = 0; j < 12; j++)
                {
                    DateTime mes = Convert.ToDateTime(fila["Mes"+j]);
                    if ((mes < contrato.FechaFin) || (!Convert.ToBoolean(fila["Pintar" + j]))) continue;
                    ObtenerFechaAnterior(ref lista, mes, contrato.Id);
                    var proyeccion = new ProyeccionDto();
                    proyeccion.FechaInicio = mes;
                    proyeccion.FechaFin = mes;
                    proyeccion.Monto = Convert.ToSingle(fila["Monto" + j].ToString());
                    proyeccion.Porcentaje = Convert.ToSingle(fila["Porcentaje" + j].ToString());
                    proyeccion.Contrato = contrato;
                    proyeccion.Estado = 1;
                    lista.Add(proyeccion);
                }
            }

            foreach (var dto in lista.Where(dto => dto.FechaInicio == dto.FechaFin))
                dto.FechaFin = new DateTime(DateTime.Now.AddYears(3).Year, 12, dto.FechaFin.Day);
            List<ProyeccionDto> listaEliminar = new List<ProyeccionDto>();
            foreach (var contrato in _vista.ListaContratos)
                listaEliminar.AddRange(_controlador.ConsultarProyeccion(contrato));
            _controlador.AgregarProyeccion(lista, listaEliminar);
        }

        private bool ObtenerFechaAnterior(ref List<ProyeccionDto> lista, DateTime fecha, long idContrato)
        {
            if(lista.Count > 0)
            foreach (var dto in lista.Where(dto => (dto.FechaInicio < fecha) && (dto.FechaFin == dto.FechaInicio) && dto.Contrato.Id == idContrato))
            {
                dto.FechaFin = fecha;
            }

            return true;
        }

        /// <summary> Metodo que obtiene el monto del contrato para la fecha indicada </summary>
        /// <param name="lista"></param>
        /// <param name="fecha"></param>
        /// <returns></returns>
        private float ObtenerMontoContrato(List<ContratoPensionDto> lista, DateTime fecha, ContratoDto contrato )
        {
            float retorno = 0;
            if(lista.Count > 0)
            {
                var valor = lista.Where(
                    dto => (dto.Contrato.Id == contrato.Id && (dto.FechaInicio < fecha) && (dto.FechaFin > fecha)) || (dto.FechaInicio == fecha));
                if (valor.Any())
                {
                    retorno = valor.Select(dto => dto.Monto).FirstOrDefault();
                }
                else
                {
                    foreach (var dto in lista.Where(dto => dto.Contrato.Id == contrato.Id))
                        if (dto.FechaFin == fecha)
                            retorno = dto.Monto;
                        else if (dto.FechaInicio == fecha)
                            retorno = dto.Monto;
                }
            }
            return retorno;
        }


        /// <summary> Metodo que obtiene el monto del contrato para la fecha indicada </summary>
        /// <param name="lista"></param>
        /// <param name="fecha"></param>
        /// <returns></returns>
        private float ObtenerPorcentajeContrato(List<ContratoPensionDto> lista, DateTime fecha, ContratoDto contrato)
        {
            float retorno = 0;
            if (lista.Count > 0)
            {
                var valor = lista.Where(
                    dto => (dto.Contrato.Id == contrato.Id && (dto.FechaInicio < fecha) && (dto.FechaFin > fecha)) || (dto.FechaInicio == fecha));
                if (valor.Any())
                {
                    retorno = valor.Select(dto => dto.Porcentaje).FirstOrDefault();
                }
                else
                {
                    foreach (var dto in lista.Where(dto => dto.Contrato.Id == contrato.Id))
                        if (dto.FechaFin == fecha)
                            retorno = dto.Porcentaje;
                        else if (dto.FechaInicio == fecha)
                            retorno = dto.Porcentaje;
                }
            }
            return retorno;
        }

    }
}
